package l2ft.gameserver.dao;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.List;

import l2ft.gameserver.database.DatabaseFactory;
import l2ft.gameserver.model.Effect;
import l2ft.gameserver.model.Playable;
import l2ft.gameserver.model.Player;
import l2ft.gameserver.model.Skill;
import l2ft.gameserver.model.instances.SummonInstance;
import l2ft.gameserver.skills.EffectType;
import l2ft.gameserver.skills.effects.EffectTemplate;
import l2ft.gameserver.stats.Env;
import l2ft.gameserver.tables.SkillTable;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class EffectsDAO
{
	private static final int SUMMON_SKILL_OFFSET = 100000;
	private static final Logger _log = LoggerFactory.getLogger(EffectsDAO.class);
	private static final EffectsDAO _instance = new EffectsDAO();

	EffectsDAO()
	{
		//
	}

	public static EffectsDAO getInstance()
	{
		return _instance;
	}

	public void restoreEffects(Playable playable)
	{
		int objectId, id;
		if(playable.isPlayer())
		{
			objectId = playable.getObjectId();
			id = ((Player)playable).getActiveClassId();
		}
		else if(playable.isSummon())
		{
			objectId = playable.getPlayer().getObjectId();
			id = ((SummonInstance)playable).getEffectIdentifier() + SUMMON_SKILL_OFFSET;
		}
		else
			return;

		try(Connection con = DatabaseFactory.getConnection())
		{
			try(PreparedStatement statement = con.prepareStatement("SELECT `skill_id`,`skill_level`,`effect_count`,`effect_cur_time`,`duration` FROM `character_effects_save` WHERE `object_id`=? AND `id`=? ORDER BY `order` ASC"))
			{
				statement.setInt(1, objectId);
				statement.setInt(2, id);
				try(ResultSet rset = statement.executeQuery())
				{
					while(rset.next())
					{
						int skillId = rset.getInt("skill_id");
						int skillLvl = rset.getInt("skill_level");
						int effectCount = rset.getInt("effect_count");
						long effectCurTime = rset.getLong("effect_cur_time");
						long duration = rset.getLong("duration");
		
						Skill skill = SkillTable.getInstance().getInfo(skillId, skillLvl);
						if(skill == null)
							continue;
		
						for(EffectTemplate et : skill.getEffectTemplates())
						{
							if(et == null)
								continue;
							Env env = new Env(playable, playable, skill);
							Effect effect = et.getEffect(env);
							if(effect == null || effect.isOneTime())
								continue;
		
							effect.setCount(effectCount);
							effect.setPeriod(effectCount == 1 ? duration - effectCurTime : duration);
		
							playable.getEffectList().addEffect(effect);
						}
					}
				}
			}
			
			try(PreparedStatement statement = con.prepareStatement("DELETE FROM character_effects_save WHERE object_id = ? AND id=?"))
			{
				statement.setInt(1, objectId);
				statement.setInt(2, id);
				statement.execute();
			}
		}
		catch(final Exception e)
		{
			_log.error("Could not restore active effects data!", e);
		}
	}

	public void deleteEffects(int objectId, int skillId)
	{
		try(Connection con = DatabaseFactory.getConnection();
				PreparedStatement statement = con.prepareStatement("DELETE FROM character_effects_save WHERE object_id = ? AND id=?"))
		{
			statement.setInt(1, objectId);
			statement.setInt(2, SUMMON_SKILL_OFFSET + skillId);
			statement.execute();
		}
		catch(final Exception e)
		{
			_log.error("Could not delete effects active effects data!" + e, e);
		}
	}

	public void insert(Playable playable)
	{
		int objectId, id;
		if(playable.isPlayer())
		{
			objectId = playable.getObjectId();
			id = ((Player)playable).getActiveClassId();
		}
		else if(playable.isSummon())
		{
			objectId = playable.getPlayer().getObjectId();
			id = ((SummonInstance)playable).getEffectIdentifier() + SUMMON_SKILL_OFFSET;
		}
		else
			return;

		List<Effect> effects = playable.getEffectList().getAllEffects();
		if(effects.isEmpty())
			return;

		try(Connection con = DatabaseFactory.getConnection();
				PreparedStatement statement = con.prepareStatement("INSERT IGNORE INTO `character_effects_save` (`object_id`,`skill_id`,`skill_level`,`effect_count`,`effect_cur_time`,`duration`,`order`,`id`) VALUES(?,?,?,?,?,?,?,?)"))
		{
			int order = 0;
			for(Effect effect : effects)
				if(effect != null && effect.isInUse() && !effect.getSkill().isToggle() && effect.getEffectType() != EffectType.HealOverTime && effect.getEffectType() != EffectType.CombatPointHealOverTime)
				{
					if(effect.isSaveable())
					{
						statement.setInt(1, objectId);
						statement.setInt(2, effect.getSkill().getId());
						statement.setInt(3, effect.getSkill().getLevel());
						statement.setInt(4, effect.getCount());
						statement.setLong(5, effect.getTime());
						statement.setLong(6, effect.getPeriod());
						statement.setInt(7, order);
						statement.setInt(8, id);
						statement.addBatch();
					}
					while((effect = effect.getNext()) != null && effect.isSaveable())
					{
						statement.setInt(1, objectId);
						statement.setInt(2, effect.getSkill().getId());
						statement.setInt(3, effect.getSkill().getLevel());
						statement.setInt(4, effect.getCount());
						statement.setLong(5, effect.getTime());
						statement.setLong(6, effect.getPeriod());
						statement.setInt(7, order);
						statement.setInt(8, id);
						statement.addBatch();
					}
					order++;
				}

			if(order > 0)
				statement.executeBatch();
		}
		catch(final Exception e)
		{
			_log.error("Could not store active effects data!", e);
		}
	}
}
